<!--当你使用这个组件时,请注意在其外围的盒子style中设置line-height,否则数字可能会无法对齐-->
<template>
  <div class="_digi-scroller"
    :style="{ height: `${height}px`, width: `${ changeInfo ? width * changeInfo.to.length : 0}px` }"
    ref="myDigiScroller">
    <div class="placeholder" ref="myPlaceHolder">0</div>
    <div :style="{ left: `-${width}px` }" class="digi-zone" v-if="changeInfo">
      <SingleNumberRoll class="single-digi" v-for="(digi, index) in changeInfo.to" :key="changeInfo.to.length - index"
        :from="changeInfo.from[index]" :to="digi" :height="height" />
    </div>
  </div>
</template>
<script>
import SingleNumberRoll from "@/components/SingleNumberRoll.vue";
export default {
  name: "NumberRoll",
  components: { SingleNumberRoll },
  data() {
    return {
      height: 0,
      width: 0,
      inView: false,
      listener: undefined,
      scrollTimer: undefined // 滚动监听节流用
    }
  },
  props: {
    from: {
      type: [Number, String],
      default: 0
    },
    to: {
      type: [Number, String],
      default: 0
    },
    scrollContainer: {
      default: undefined
    }
  },
  computed: {
    changeInfo() {
      if ((this.from || this.from === 0) && (this.to || this.to === 0) && this.inView) {
        // from 和 to 都接收到了之后
        const len = Math.max(String(this.to).length, String(this.from).length);
        // eslint-disable-next-line prefer-spread
        const from = `${Array.apply(null, Array(len)).map(() => '0').join('')}${this.from}`.slice(-len);
        // eslint-disable-next-line prefer-spread
        const to = `${Array.apply(null, Array(len)).map(() => '0').join('')}${this.to}`.slice(-len);
        return { from, to };
      }
      return false;
    },
    checkRectBounding() {
      if (!this.$refs.myDigiScroller) return false;
      const viewPortHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
      const rect = this.$refs.myDigiScroller.getBoundingClientRect() || {};
      const { top } = rect;
      return +top <= viewPortHeight + 100; // 由于存在节流，这里判定范围扩大一点
    }
  },
  methods: {
    checkObserverSupport() {
      return 'IntersectionObserver' in window
        && 'IntersectionObserverEntry' in window
        && 'intersectionRatio' in window.IntersectionObserverEntry.prototype;
    },
    checkIntoViewPollyfill() {
      if (this.scrollTimer) return;
      const isInView = this.checkRectBounding();
      this.scrollTimer = setTimeout(() => { this.scrollTimer = undefined; }, 100); // 节流
      if (isInView) {
        console.log('scroll listener: digi scroller into view');
        this.scrollListenContainer.removeEventListener('scroll', this.checkIntoViewPollyfill);
        // eslint-disable-next-line no-unused-expressions
        this.scrollTimer && clearTimeout(this.scrollTimer);
        this.scrollTimer = undefined;
        this.inView = true;
      }
    },
    checkIntoView() {
      if (this.checkObserverSupport()) {
        // eslint-disable-next-line no-unused-expressions
        this.listener && this.listener.disconnect();
        this.listener = new IntersectionObserver(
          entries => {
            const { intersectionRatio } = entries[0];
            if (intersectionRatio > 0) {
              this.listener.disconnect();
              console.log('intersection observer: digi scroller into view');
              this.listener = undefined;
              this.inView = true;
            }
          }
        );
        this.listener.observe(this.$refs.myDigiScroller);
      } else if (this.checkRectBounding()) {
        this.inView = true;
      } else {
        if (!this.scrollContainer) {
          this.scrollListenContainer = window;
        } else if (typeof this.scrollContainer === 'string') {
          this.scrollListenContainer = document.querySelector(this.scrollContainer);
        } else {
          this.scrollListenContainer = this.scrollContainer;
        }
        this.scrollListenContainer.removeEventListener('scroll', this.checkIntoViewPollyfill);
        this.scrollListenContainer.addEventListener('scroll', this.checkIntoViewPollyfill);
      }
    }
  },
  mounted() {
    const { clientHeight, clientWidth } = this.$refs.myPlaceHolder;
    this.height = clientHeight;
    this.width = clientWidth;
    this.checkIntoView();
  },
  beforeDestroy() {
    if (this.listener) {
      this.listener.disconnect();
      this.listener = undefined;
    }
    if (this.scrollListenContainer) {
      this.scrollListenContainer.removeEventListener('scroll', this.checkIntoViewPollyfill);
    }
    // eslint-disable-next-line no-unused-expressions
    this.scrollTimer && clearTimeout(this.scrollTimer);
    this.scrollTimer = undefined;
  }
}
</script>
<style>
._digi-scroller {
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
}

.placeholder {
  display: inline-block;
  opacity: 0;
}

.digi-zone {
  position: relative;
  display: inline-block;
}
</style>